import sys
import hashlib
import base64
from twisted.internet.protocol import Factory
from twisted.protocols.basic import LineReceiver
from twisted.internet import reactor
from twisted.python import log
import types
from EventHandler import EventHandler


def parse_headers(msg):
    headers = {}
    header, data = msg.split('\r\n\r\n', 1)
    for line in header.split('\r\n')[1:]:
        key, value = line.split(': ', 1)
        headers[key] = value
    headers['data'] = data
    return headers

def generate_token(msg):
    key = msg + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
    ser_key = hashlib.sha1(key).digest()
    return base64.b64encode(ser_key)

def parse_data(msg):
    if type(msg) == types.NoneType or len(msg) < 2:
        return None
    v = ord(msg[1]) & 0x7f
    if v == 0x7e:
        p = 4
    elif v == 0x7f:
        p = 10
    else:
        p = 2
    mask = msg[p:p+4]
    data = msg[p+4:]
  
    return ''.join([chr(ord(v) ^ ord(mask[k%4])) for k, v in enumerate(data)])

class Chat(LineReceiver):
    def __init__(self, users,type = 'tcp'):
        self.users = users
        self.name = None
        self.state = "GETNAME"
        self.type = type
        if type == 'websocket':
            self.setRawMode()
        #self.Eventhandle = EventHandler()

    def connectionMade(self):
        if self.type == 'websocket':
            self.conmade = False
            pass
        else:
            self.client_ip = self.transport.getPeer()
            log.msg("client is {0!s}".format(self.client_ip))
            self.sendLine("What's your name?")

    def connectionLost(self, reason):
        if self.users.has_key(self.name):
            del self.users[self.name]

    def lineReceived(self, line):
        log.msg(line)
        if self.state == "GETNAME":
            self.handle_GETNAME(line)
        else:
            self.handle_CHAT(line)
            
    def rawDataReceived(self, data):
        if self.conmade == False:
            log.msg("building connection...{0!s}".format(self.client_ip))
        else:
            RecvData = parse_data(data)
            #connection.send('%c%c%s' % (0x81, len(info), info))
            EventHandler().handlemsg(self, RecvData)
            self.transport.write('%c%c%s' % (0x81, len(RecvData), RecvData))
            return
        headers = parse_headers(data);
        if not headers.has_key('Sec-WebSocket-Key'):
            print "Got websocket protocol which is not support"
            return
        token = generate_token(headers['Sec-WebSocket-Key'])     
        self.sendLine('\
HTTP/1.1 101 Switching Protocols\r\n\
Upgrade: WebSocket\r\n\
Connection: Upgrade\r\n\
Sec-WebSocket-Accept: %s\r\n' % token)
        self.conmade = True

    def handle_GETNAME(self, name):
        if self.users.has_key(name):
            self.sendLine("Name taken, please choose another.")
            return
        self.sendLine("Welcome, %s!" % (name,))
        self.name = name
        self.users[name] = self
        self.state = "CHAT"

    def handle_CHAT(self, message):
        message = "<%s> %s" % (self.name, message)
        for name, protocol in self.users.iteritems():
            if protocol != self:
                protocol.sendLine(message)
    
    def echomsg(self, message):
        self.sendLine(message)
        
    def wbsoketrsp(self,data):
        message = data.encode("utf-8")
        back_str = []
        back_str.append('\x81')
        data_length = len(message)
        if data_length <= 125:
            back_str.append(chr(data_length))
        else:
            back_str.append(chr(126))
            back_str.append(chr(data_length >> 8))
            back_str.append(chr(data_length & 0xFF))
        
        back_str = "".join(back_str) + message
        self.transport.write(back_str)
        #self.transport.write('%c%c%s' % (0x81, len(data), data))
        
class ChatFactory(Factory):

    def __init__(self,type='tcp'):
        self.users = {} # maps user names to Chat instances
        self.type = type

    def buildProtocol(self, addr):
        if self.type == 'tcp':
            return Chat(self.users)
        else:
            return Chat(self.users,self.type)
lobby = []
EventHandler(lobby)
log.startLogging(sys.stdout)
reactor.listenTCP(8123, ChatFactory('websocket'))
#reactor.listenTCP(8123, ChatFactory())
reactor.run()